package com.jy.modules.cims.common.open.api.util;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;

import org.apache.commons.io.IOUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;

public abstract class HttpClientUtils {
	static HttpClient client = null;

	static {
		PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
		cm.setMaxTotal(128);
		cm.setDefaultMaxPerRoute(128);
		client = HttpClients.custom().setConnectionManager(cm).build();
	}


	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static String postForm(String url, Map<String, String> params, Map<String, String> headers, String charset, Integer connTimeout,
			Integer readTimeout) throws ConnectTimeoutException, SocketTimeoutException, Exception {
		HttpPost post = new HttpPost(url);
		try {
			Map.Entry<String, String> entry;
			if ((params != null) && (!params.isEmpty())) {
				List<NameValuePair> formParams = new ArrayList<NameValuePair>();
				Set<Map.Entry<String, String>> entrySet = params.entrySet();
				for (Iterator<Entry<String, String>> iter = entrySet.iterator(); iter.hasNext();) {
					entry = (Map.Entry) iter.next();
					formParams.add(new BasicNameValuePair((String) entry.getKey(), (String) entry.getValue()));
				}
				UrlEncodedFormEntity entity = null;
				if (charset != null) {
					entity = new UrlEncodedFormEntity(formParams, Charset.forName(charset.toUpperCase()));
				} else {
					entity = new UrlEncodedFormEntity(formParams, Consts.UTF_8);
				}
				post.setEntity(entity);
			}
			if ((headers != null) && (!headers.isEmpty())) {
				for (Map.Entry<String, String> en : headers.entrySet()) {
					post.addHeader((String) en.getKey(), (String) en.getValue());
				}
			}
			RequestConfig.Builder customReqConf = RequestConfig.custom();
			if (connTimeout != null) {
				customReqConf.setConnectTimeout(connTimeout.intValue());
			}
			if (readTimeout != null) {
				customReqConf.setSocketTimeout(readTimeout.intValue());
			}
			post.setConfig(customReqConf.build());
			HttpResponse res = null;
			if (url.startsWith("https")) {
				client = createSSLInsecureClient();
				res = client.execute(post);
			} else {
				res = client.execute(post);
			}
			HttpEntity resEntity = res.getEntity();
			if (resEntity != null) {
				if (charset != null) {
					return IOUtils.toString(res.getEntity().getContent(), charset.toUpperCase());
				}
				return IOUtils.toString(res.getEntity().getContent(), "UTF-8");
			}
			return null;
		} finally {
			post.releaseConnection();
			if ((url.startsWith("https")) && (client != null) && ((client instanceof CloseableHttpClient))) {
				((CloseableHttpClient) client).close();
			}
		}
	}

	public static CloseableHttpClient createSSLInsecureClient() throws GeneralSecurityException {
		SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
			public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
				return true;
			}
		}).build();
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() {
			public boolean verify(String arg0, SSLSession arg1) {
				return true;
			}

			public void verify(String host, SSLSocket ssl) throws IOException {
			}

			public void verify(String host, X509Certificate cert) throws SSLException {
			}

			public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
			}
		});
		return HttpClients.custom().setSSLSocketFactory(sslsf).build();
	}
}
